From c2494f131ca52b758f10d67092bb207217e79065 Mon Sep 17 00:00:00 2001 From: oliskoli Date: Sat, 20 Sep 2008 19:44:43 +0000 Subject: [PATCH] Add support for Jelbert GeoTagger data files (.jtr). --- Makefile.in | 5 +- geotagger.c | 286 ++++++++++++++++++++++++++++++++++++++++++++++++++++ vecs.c | 11 ++ 3 files changed, 301 insertions(+), 1 deletion(-) create mode 100644 geotagger.c diff --git a/Makefile.in b/Makefile.in index 26a798b32..bb0b9b504 100644 --- a/Makefile.in +++ b/Makefile.in @@ -59,7 +59,8 @@ ALL_FMTS=$(MINIMAL_FMTS) gtm.o gpsutil.o pcx.o cetus.o copilot.o \ wbt-200.o stmsdf.o gtrnctr.o dmtlog.o raymarine.o alan.o vitovtt.o \ ggv_log.o g7towin.o garmin_gpi.o lmx.o random.o xol.o dg-100.o \ navilink.o mtk_logger.o ik3d.o osm.o destinator.o exif.o vidaone.o \ - igo8.o gopal.o humminbird.o mapasia.o gnav_trl.o navitel.o ggv_ovl.o + igo8.o gopal.o humminbird.o mapasia.o gnav_trl.o navitel.o ggv_ovl.o \ + geotagger.o FMTS=@FMTS@ @@ -503,6 +504,8 @@ geoniche.o: geoniche.c defs.h config.h queue.h gbtypes.h zlib/zlib.h \ jeeps/gpsapp.h jeeps/gpsprot.h jeeps/gpscom.h jeeps/gpsfmt.h \ jeeps/gpsmath.h jeeps/gpsmem.h jeeps/gpsrqst.h jeeps/gpsinput.h \ jeeps/gpsproj.h garmin_tables.h +geotagger.o: geotagger.c defs.h config.h queue.h gbtypes.h zlib/zlib.h \ + zlib/zconf.h gbfile.h cet.h cet_util.h csv_util.h ggv_log.o: ggv_log.c defs.h config.h queue.h gbtypes.h zlib/zlib.h \ zlib/zconf.h gbfile.h cet.h cet_util.h inifile.h grtcirc.h \ jeeps/gpsmath.h jeeps/gps.h jeeps/../defs.h jeeps/gpsport.h \ diff --git a/geotagger.c b/geotagger.c new file mode 100644 index 000000000..7f08ad02b --- /dev/null +++ b/geotagger.c @@ -0,0 +1,286 @@ +/* + + Support for the Jelbert GeoTagger JTR data file format. + + Copyright (C) 2008 Olaf Klein, o.b.klein@gpsbabel.org + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111 USA + + */ + +#include +#include +#include +#include +#include "defs.h" +#include "csv_util.h" +#include "avltree.h" + +#define MYNAME "geotagger" + +static +arglist_t geotagger_args[] = { + ARG_TERMINATOR +}; + +static gbfile *fin, *fout; +static avltree_t *trkpts; + +static time_t +geotagger_parse_time(const char *str, struct tm *tm, int *micro) +{ + long int hms; + char *dot; + + hms = strtol(str, &dot, 10); + if (hms > 0) { + tm->tm_sec = hms % 100; + hms = hms / 100; + tm->tm_min = hms % 100; + hms = hms / 100; + tm->tm_hour = hms % 100; + + if ((*dot == '.') && (micro != NULL)) *micro = atoi(dot + 1) * 10000; + + return mkgmtime(tm); + } + else return 0; +} + +static time_t +geotagger_parse_date(const char *str, struct tm *tm) +{ + int dmy = atoi(str); + + if (dmy > 0) { + tm->tm_year = dmy % 100 + 100; + dmy = dmy / 100; + tm->tm_mon = dmy % 100 - 1; + dmy = dmy / 100; + tm->tm_mday = dmy; + return mkgmtime(tm); + } + else return 0; +} + +/******************************************************************************* +* %%% global callbacks called by gpsbabel main process %%% * +*******************************************************************************/ + +static void +geotagger_rd_init(const char *fname) +{ + fin = gbfopen(fname, "r", MYNAME); + trkpts = avltree_init(0, MYNAME); +} + +static void +geotagger_rd_deinit(void) +{ + avltree_done(trkpts); + gbfclose(fin); +} + +static void +geotagger_read(void) +{ + char *str; + int line = 0; + route_head *trk = NULL; + + while ((str = gbfgetstr(fin))) { + waypoint *wpt; + struct tm tm; + char *tmp; + int column = -1; + char valid = 'V'; + double lat, lon; + float speed, course, mcourse, mvar, mdev; + time_t time = 0; + int micros = 0; + char buf[32]; + char mvardir, mdevdir; + + line++; + + str = lrtrim(str); + if (*str == '\0') continue; + + if (strncmp(str, "GEOTAG2,", 8) != 0) + fatal(MYNAME ": Unknown or unsupported file (missing \"GEOTAG2\")!\n"); + + memset(&tm, 0, sizeof(tm)); + lat = lon = 999; + speed = course = mcourse = mvar = mdev = -1; + mvardir = mdevdir = 0; + + column = -1; + tmp = str; + while ((str = csv_lineparse(tmp, ",", "", column++))) { + tmp = NULL; + + if (*str == '\0') continue; + + switch(column) { + case 0: break; /* GEOTAG2 */ + case 1: geotagger_parse_time(str, &tm, µs); break; + case 2: valid = *str; break; + case 3: lat = ddmm2degrees(atof(str)); break; + case 4: if (*str == 'S') lat *= -1; break; + case 5: lon = ddmm2degrees(atof(str)); break; + case 6: if (*str == 'W') lon *= -1; break; + case 7: speed = KNOTS_TO_MPS(atof(str)); break; + case 8: course = atof(str); break; + case 9: geotagger_parse_date(str, &tm); break; + case 13: mcourse = atof(str); break; + case 14: mdev = atof(str); break; + case 15: mdevdir = *str; break; + case 16: mvar = atof(str); break; + case 17: mvardir = *str; break; + default: + break; + } + } + + if ((lat == 999) || (lon == 999) || (valid != 'A')) continue; + + if (tm.tm_year > 0) time = mkgmtime(&tm); + else time = 0; + + /* check for duplicates as suggested in format description */ + + snprintf(buf, sizeof(buf), "%.6f\01\%.6f\01\%ld", lat, lon, (long)time); + if (avltree_find(trkpts, buf, NULL)) continue; + + wpt = waypt_new(); + + wpt->latitude = lat; + wpt->longitude = lon; + wpt->creation_time = time; + wpt->microseconds = micros; + if (speed >= 0) WAYPT_SET(wpt, speed, speed); + if (mcourse >= 0) { + course = mcourse; + if (mvar >= 0) { + if (mvardir == 'W') course += mvar; + else if (mvardir == 'E') course -= mvar; + } + if (mdev >= 0) { + if (mdevdir == 'W') course += mdev; + else if (mdevdir == 'E') course -= mdev; + } + } + if (course >= 0) WAYPT_SET(wpt, course, course); + + if (trk == NULL) { + trk = route_head_alloc(); + track_add_head(trk); + } + + avltree_insert(trkpts, buf, wpt); + track_add_wpt(trk, wpt); + xfree(str); + } +} + +static void +geotagger_wr_init(const char *fname) +{ + fout = gbfopen(fname, "wb", MYNAME); +} + +static void +geotagger_wr_deinit(void) +{ + gbfclose(fout); +} + +static void +geotagger_trkpt_disp_cb(const waypoint *wpt) +{ + char *str, *tmp; + char stime[10], sdate[7], scourse[6], sspeed[8]; + struct tm tm; + + if (wpt->creation_time > 0) { + tm = *gmtime(&wpt->creation_time); + tm.tm_year += 1900; + tm.tm_mon += 1; + snprintf(sdate, sizeof(sdate), "%02d%02d%02d", tm.tm_mday, tm.tm_mon, tm.tm_year % 100); + snprintf(stime, sizeof(stime), "%02d%02d%02d.%02d", tm.tm_hour, tm.tm_min, tm.tm_sec, wpt->microseconds / 10000); + if (wpt->microseconds / 10000 == 0) stime[6] = 0; + } + else { + stime[0] = 0; + sdate[0] = 0; + } + if (WAYPT_HAS(wpt, speed) && (wpt->speed >= 0)) + snprintf(sspeed, sizeof(sspeed), "%.1f", MPS_TO_KNOTS(wpt->speed)); + else sspeed[0] = 0; + if (WAYPT_HAS(wpt, course) && (wpt->course >= 0)) + snprintf(scourse, sizeof(scourse), "%.1f", wpt->course); + else scourse[0] = 0; + + xasprintf(&str, "GEOTAG2,%s,%c,%09.4f,%c,%010.4f,%c,%s,%s,%s,,E,A", + stime, + time > 0 ? 'A' : 'V', + fabs(degrees2ddmm(wpt->latitude)), + wpt->latitude < 0 ? 'S' : 'N', + fabs(degrees2ddmm(wpt->longitude)), + wpt->longitude < 0 ? 'W' : 'E', + sspeed, + scourse, + sdate); + + xasprintf(&tmp, "%s*%02X", str, nmea_cksum(str)); + xfree(str); + str = tmp; + + xasprintf(&tmp, "%s,,,E,,E*%02X\n", str, nmea_cksum(str)); + xfree(str); + str = tmp; + + gbfputs(str, fout); + xfree(str); +} + +static void +geotagger_write(void) +{ + track_disp_all(NULL, NULL, geotagger_trkpt_disp_cb); +} + +/**************************************************************************/ + +ff_vecs_t geotagger_vecs = { + ff_type_file, + { + ff_cap_none, /* waypoints */ + ff_cap_read | ff_cap_write, /* tracks */ + ff_cap_none /* routes */ + }, + geotagger_rd_init, + geotagger_wr_init, + geotagger_rd_deinit, + geotagger_wr_deinit, + geotagger_read, + geotagger_write, + NULL, + geotagger_args, + CET_CHARSET_ASCII, 0 /* ascii is the expected character set */ + /* not fixed, can be changed through command line parameter */ +}; + +/**************************************************************************/ diff --git a/vecs.c b/vecs.c index 9ce270d06..abfb2f3c8 100644 --- a/vecs.c +++ b/vecs.c @@ -147,6 +147,9 @@ extern ff_vecs_t mapasia_tr7_vecs; extern ff_vecs_t gnav_trl_vecs; extern ff_vecs_t navitel_trk_vecs; extern ff_vecs_t ggv_ovl_vecs; +#if CSVFMTS_ENABLED +extern ff_vecs_t geotagger_vecs; +#endif static vecs_t vec_list[] = { @@ -844,6 +847,14 @@ vecs_t vec_list[] = { "Geogrid-Viewer ascii overlay file (.ovl)", "ovl" }, +#if CSVFMTS_ENABLED + { + &geotagger_vecs, + "geotagger", + "Jelbert GeoTagger data file", + "jtr" + }, +#endif #endif // MAXIMAL_ENABLED { -- 2.30.2